home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
DiskUtil
/
Crunch
/
XFH.lha
/
XFH
/
SRC
/
LOCK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-15
|
21KB
|
679 lines
/* lock.c - Lock-related stuff for the cfs file system.
Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
This file is part of XFH, the compressing file system handler.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "CFS.h"
#include <string.h>
#include <dossupport.h>
/*
* RawCFSLock() is the low-lewel LOCATE_OBJECT function of the CFS file
* system. It takes a simple filename (that is, no path specification),
* a lock to the parent directory, and a 'mode' value as arguments. A
* special case occurs for a null name, in which case it just returns
* a copy of the passed lock.
* NOTE: 'directory/' is a valid name if it's a directory.
*/
struct CFSLock *RawCFSLock(glb glob, struct CFSLock *lock,
char * name, LONG mode ){
LONG saveioerr;
if( name && *name ){
/* Here is the place to check whether the lock refers to a
* directory in the underlying file system, or if it is in fact
* a directory in an archieve. This code is for the former case: */
if( lock->objtype == XOBJECT ){
struct FileLock *xlock;
if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
debug(("Error: RawCFSLock(): Could not obtain lock: %ld.\n",glob->ioerr));
return NULL;
}
if( !xExamine( glob, xlock, &glob->fib1 ) ){
debug(("Error: RawCFSLock(): Cannot examine() object: %ld\n",glob->ioerr));
saveioerr = glob->ioerr;
xUnLock( glob, xlock );
glob->ioerr = saveioerr;
return NULL;
}
if( glob->fib1.fib_DirEntryType > 0 ){
struct CFSLock *newlock;
/* A directory. */
newlock = XObjMakeLock(glob, xlock, mode);
if( !newlock ){
saveioerr = glob->ioerr;
xUnLock(glob, xlock);
glob->ioerr = saveioerr;
}
return newlock;
}else{
struct FileHandle *xfh;
LONG filetype;
/* A plain file. Determine its type. */
/* First open the file. If the lock is to be exclusive, */
/* we need to xUnLock() it while examining the file (BAD!) */
/* This means that there's an ever so slight change that */
/* the file will go away inbetween the xClose() and xLock(). */
/* It might even have come back in a new disguise! sigh... */
if( mode == EXCLUSIVE_LOCK ){
debug(("RawCFSLock(): Temporarely UnLock()'ing...\n"));
xUnLock(glob, xlock);
xlock = NULL;
xfh = xOpen( glob, lock->xlock, name, MODE_OLDFILE );
}else{
xfh = xOpenFromCopyOfLock( glob, xlock );
}
if( !xfh ){
debug(("Error: RawCFSLock(): Cannot Open() file: %ld.\n",glob->ioerr));
if( xlock ){
saveioerr = glob->ioerr;
xUnLock(glob, xlock);
glob->ioerr = saveioerr;
}
return NULL;
}
filetype = xFileType(glob, xfh);
xClose(glob, xfh);
if(!xlock){
if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
debug(("Error: RawCFSLock(): Could not re-Lock() the file: %ld.\n",glob->ioerr));
return NULL;
}
}
/* ToDo: this shouldn't be implemented as an ugly switch(). */
switch(filetype){
case XOBJECT:{
struct CFSLock *newlock;
newlock = XObjMakeLock(glob, xlock, mode);
if( !newlock ){
saveioerr = glob->ioerr;
xUnLock( glob, xlock );
glob->ioerr = saveioerr;
}
return newlock;
}
case XPKOBJECT:{
struct XpkLock *newlock;
newlock = XpkMakeLock(glob, xlock, mode);
if( !newlock ){
saveioerr = glob->ioerr;
xUnLock(glob, xlock);
glob->ioerr = saveioerr;
}
return (struct CFSLock *)newlock;
}
default:
debug(("ERROR: RawCFSLock(): unsupported file type %ld.\n",filetype));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return NULL;
}
}
}else{
debug(("** PANIC **: bad object type in lock: %ld\n",lock->objtype));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return NULL;
}
}else{
/* A Null name was passed. If the parent lock is of the right type,
* just DupLock() it. Otherwise, signal an error.
* (Duplock() will catch the case of an exclusive lock).
*/
if( mode == lock-> mode ){
return CFSDupLock( glob, lock );
}else{
glob->ioerr = ERROR_OBJECT_IN_USE;
return NULL;
}
}
}
/* And DOS said: let there be devices...
* So hardwire a CFSLock to serve as our root lock.
*/
struct CFSLock *makerootlockdayone(glb glob){
return XObjMakeLock(glob, glob->xrootlock, ACCESS_READ);
}
/*
* Create a struct FileLock around a CFSLock for returning to caller.
*/
struct FileLock * CreateFileLock( glb glob, struct CFSLock *lock ){
struct FileLock *xlock;
if( !dalloc(xlock) ){
OUTOFMEM;
return NULL;
}
/* Place any linking of filelocks into a list here. */
xlock -> fl_Key = (LONG) lock;
xlock -> fl_Access = lock -> mode;
xlock -> fl_Task = glob -> dosport;
xlock -> fl_Volume = c2b(glob -> volnode);
return xlock;
}
/*
* This is the function that does all the main parsing of path strings.
* It's purpose is to lock the parent directory of a file or dir, and
* return a pointer to the actual filename. A special case occurs for
* NULL filenames (either "" or "name:") - here the actual lock is
* returned, and the name set to "".
*
* In case of an error, the name is set to "", and a NULL lock is returned.
*
* NOTE: This will fail to correctly handle a path like '...//' - it
* will lock the directory and return a NULL name. This will present
* a problem if someone tries to obtain an exclusive lock on such a path.
*/
struct CFSLock *CFSLockParent( glb glob, struct CFSLock *parentlock,
char **nameptr ){
char *p,*q,*path,*name;
struct CFSLock *lock,*childlock;
int len;
/* Watch out for a NULL name. */
if(!*nameptr) *nameptr = "";
/* Allocate a copy of the path so that we can modify it. */
len = strlen(*nameptr);
if( !(name = dosalloc( len+1 )) ){
OUTOFMEM;
*nameptr += len; /* Set to empty string. */
return NULL;
}
strcpy( name, *nameptr);
path = name;
/* A NULL parent lock is equal to the rootlock. */
if(!parentlock) parentlock = glob->rootlock;
/* Now check for an absolute path, ie '...:...' */
if( p=strchr(name,':') ){
/* Got an absolute path. This is either an assign (or the device /
* volume name, which is treated the same way), or a root
* specification (like ':system/cli'). */
if( p==name ){ /* get the root dir. */
parentlock = glob->rootlock;
}
#ifndef NONSTRICT
else{
/* The assign/device/volume name was used by dos.library to
* find our process id and the parent lock. It is of no use
* to the handler.*/
/* 'Assign' allows silly names like '1/2:', but some other
* commands have trouble with this. Flag these names as invalid. */
if( q=strchr(name,'/') ){
if( q<p ){
debug(("Error: silly device name '%s'/n",name));
glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
dosfree( name );
*nameptr += len;
return NULL;
}
}
}
#endif
path = p+1; /* Point past ':'. */
#ifndef NONSTRICT
/* Disallow more than one ':' char in name. */
if( strchr(path,':') ){
debug(("Error: multiple ':' char in name '%s'.\n",name));
glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
dosfree( name);
*nameptr += len;
return NULL;
}
#endif
}
/* Now look through the path specification. */
if( !(lock = CFSDupLock( glob, parentlock )) ){
/* Couldn't DupLock the parent. Hence we must use a reference. */
debug(("CFSLockParent(): Cannot DupLock() the passed parent dir: %ld - using reference.\n",glob->ioerr));
XObjAddReferenceToLock(glob, parentlock);
lock = parentlock;
/* NOTE: We now have a dangerous double reference to the
* lock. Notably, the lock will be CFSUnLock()'ed two
* times.
*/
}
for(;;){
p = path;
if( !*p ) break; /* If p is the null string, then lock is ok now. */
path = strchr( p, '/' );
if( path ){
*path++ = '\0';
if( !*path && path != p+1 ){
break; /* Last component is 'name/'. */
}
}else{
break; /* Last component is 'name'. */
}
/* At this point, p holds a null-terminated path component. */
childlock = p+1 == path ?
CFSParentDir(glob,lock) :
RawCFSLock(glob,lock,p,SHARED_LOCK);
if( !childlock ){
LONG saveioerr;
/* Some kind of error happened while locking the path component.
* Report this error back to caller. */
saveioerr = glob->ioerr; /* Save I/O error code. */
CFSUnLock( glob, lock);
if( p+1 == path && !glob->ioerr) /* Attempt to use '/' past root */
glob->ioerr = ERROR_OBJECT_NOT_FOUND;
else
glob->ioerr = saveioerr; /* Restore for IoErr(). */
dosfree( name );
*nameptr += len;
return NULL;
}
CFSUnLock( glob, lock);
lock=childlock;
if( !CFSExamine(glob, childlock, &glob->fib1) ){
/* Error examining component. */
CFSUnLock(glob, lock);
dosfree( name );
*nameptr += len;
return NULL;
}
if( glob->fib1.fib_DirEntryType < 0 ){
/* this component in the path is not a directory, so return
* an error. */
debug(("Error: CFSLockParent(): Plain file used in path.\n"));
CFSUnLock(glob, lock);
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
dosfree( name );
*nameptr += len;
return NULL;
}
}
*nameptr += (p - name); /* Point to equivalent of *p in 'name'. */
dosfree( name );
return lock;
}
/*
* This function handles the ACTION_LOCATE_OBJECT request.
*/
struct CFSLock * CFSLock(glb glob,struct CFSLock * parentlock,
char * name,LONG mode){
struct CFSLock *lock,*parent;
LONG ioerrsave;
/* Lock the parent directory, and set 'name' to point to the actual
* name. For a path like 'name:', lock the file/dir and point name to
* "" (RawCFSLock() will handle this case).
*/
if(!(parent = CFSLockParent(glob, parentlock, &name ))){
return NULL;
}
debug(("CFSLock: parent=%lx, name='%s'\n",parent,name));
/* Now Lock the file or dir. */
lock = RawCFSLock( glob, parent, name, mode );
ioerrsave = glob->ioerr;
CFSUnLock( glob, parent );
glob->ioerr = ioerrsave;
return lock;
}
struct CFSLock *CFSDupLock( glb glob, struct CFSLock *lock ){
if( !lock ) return 0L;
return (*lock->f->DupLock) (glob,lock);
}
struct CFSLock *CFSParentDir( glb glob, struct CFSLock *lock){
if( !lock ) return NULL;
else if(!lock->f){
debug(("** PANIC **: CFSParentDir(): NULL action function.\n"));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}else return (*lock->f->Parent)(glob, lock);
}
struct CFSLock *CFSParentFH( glb glob, struct CFSFH *fh){
if( !fh ) return NULL;
else if(!fh->f){
debug(("** PANIC **: CFSParentDir(): NULL action function.\n"));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}else return (*fh->f->ParentOfFH)(glob, fh);
}
BOOL CFSUnLock( glb glob,struct CFSLock *lock){
if( !lock ) return 0L; /* No really sensible error possible. */
else if(!lock->f){
debug(("** PANIC **: CFSUnLock(): NULL action function.\n"));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}else return (*lock->f->UnLock)(glob, lock);
}
BOOL CFSExamine(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
if( !lock ){
return DOSFALSE; /* No really sensible error possible. */
}else if( lock->f ){
return (*lock->f->Examine)( glob, lock, fib );
} else {
debug(("** PANIC **: NULL object action func Examine() in lock.\n"));
return DOSFALSE;
}
}
BOOL CFSExamineNext(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
if( !lock ){
return DOSFALSE; /* No really sensible error possible. */
}else if( lock->f ){
return (*lock->f->ExNext)( glob, lock, fib );
} else {
debug(("** PANIC **: NULL object action func ExNext() in lock.\n"));
return DOSFALSE;
}
}
BOOL CFSExamineFH(glb glob, struct CFSFH *fh, struct FileInfoBlock *fib){
if( !fh ){
return DOSFALSE; /* No really sensible error possible. */
}else if( fh->f ){
return (*fh->f->ExamineFH)( glob, fh, fib );
} else {
debug(("** PANIC **: NULL object action func ExamineFH() in handle.\n"));
return DOSFALSE;
}
}
struct CFSLock *CFSCreateDir( glb glob, struct CFSLock *parent, char *name ){
struct CFSLock *lock;
/* Lock the parent directory, and set 'name' to point to the actual
* name. For a path like 'name:', lock the file/dir and point name to
* "" (RawCFSLock() will handle this case).
*/
if(!(parent = CFSLockParent(glob, parent, &name ))){
return NULL;
}else if( parent->f ){
LONG saveioerr;
lock = (*parent->f->CreateDir)( glob, parent, name );
if( !lock ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent );
if( !lock ) glob->ioerr = saveioerr;
return lock;
}else{
debug(("** PANIC **: NULL object action func CreateDir() in lock.\n"));
CFSUnLock( glob, parent );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return NULL;
}
}
/* CFSDeleteFile(): Delete a file or directory.
*
* Just passes control to the appropriate lock-specific call.
* NOTE: It's up to the lock-specific functions to check that an attempt
* to delete a non-empty directory is rejected.
*/
BOOL CFSDeleteFile( glb glob, struct CFSLock *parent, char *name ){
if(!(parent = CFSLockParent(glob, parent, &name ))){
return DOSFALSE;
}else if( parent->f ){
LONG saveioerr;
BOOL err;
err = (*parent->f->DeleteFile)( glob, parent, name );
if( !err ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent );
if( !err ) glob->ioerr = saveioerr;
return err;
}else{
debug(("** PANIC **: NULL object action func DeleteFile() in lock.\n"));
CFSUnLock( glob, parent );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
/* CfsRename(): Rename files within the file system.
*
* A problem arises if someone tries to rename between two directory-
* locks of different types (ie. a lharc-archieve and an UFS directory).
* This function passes control to the FROM-locktype rename function. It's
* up to this function to check the type of the destination directory
* and take an appropriate action.
*/
BOOL CFSRename( glb glob, struct CFSLock *parent1, char *name1, struct CFSLock *parent2, char *name2 ){
if(!(parent1 = CFSLockParent(glob, parent1, &name1 ))){
return DOSFALSE;
}
if(!(parent2 = CFSLockParent(glob, parent2, &name2 ))){
LONG saveioerr = glob->ioerr;
CFSUnLock( glob, parent1 );
glob->ioerr = saveioerr;
return DOSFALSE;
}
if( parent1->f ){
LONG saveioerr;
BOOL err;
err = (*parent1->f->Rename)( glob, parent1, name1, parent2, name2 );
if( !err ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent1 );
CFSUnLock( glob, parent2 );
if( !err ) glob->ioerr = saveioerr;
return err;
}else{
debug(("** PANIC **: NULL object action func Rename() in lock.\n"));
CFSUnLock( glob, parent1 );
CFSUnLock( glob, parent2 );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSSetProtection( glb glob, struct CFSLock *parent, char *name, LONG bits ){
if(!(parent = CFSLockParent(glob, parent, &name ))){
return DOSFALSE;
}else if( parent->f ){
LONG saveioerr;
BOOL err;
err = (*parent->f->SetProtection)( glob, parent, name, bits );
if( !err ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent );
if( !err ) glob->ioerr = saveioerr;
return err;
}else{
debug(("** PANIC **: NULL object action func SetProtection() in lock.\n"));
CFSUnLock( glob, parent );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSSetComment( glb glob, struct CFSLock *parent, char *name, char *comment ){
if(!(parent = CFSLockParent(glob, parent, &name ))){
return DOSFALSE;
}else if( parent->f ){
LONG saveioerr;
BOOL err;
err = (*parent->f->SetComment)( glob, parent, name, comment );
if( !err ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent );
if( !err ) glob->ioerr = saveioerr;
return err;
}else{
debug(("** PANIC **: NULL object action func SetComment() in lock.\n"));
CFSUnLock( glob, parent );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSSetDate( glb glob, struct CFSLock *parent, char *name, struct DateStamp *ds ){
if(!(parent = CFSLockParent(glob, parent, &name ))){
return DOSFALSE;
}else if( parent->f ){
LONG saveioerr;
BOOL err;
err = (*parent->f->SetFileDate)( glob, parent, name, ds );
if( !err ) saveioerr = glob->ioerr;
CFSUnLock( glob, parent );
if( !err ) glob->ioerr = saveioerr;
return err;
}else{
debug(("** PANIC **: NULL object action func SetDate() in lock.\n"));
CFSUnLock( glob, parent );
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSMakeLink(glb glob,struct CFSLock *Parent,char *Name,LONG Dest,LONG Type)
{
if ((Parent=CFSLockParent(glob,Parent,&Name))==NULL) return DOSFALSE;
if (Parent->f)
{
BOOL Res;
LONG saveioerr;
Res=(*Parent->f->MakeLink)(glob,Parent,Name,Dest,Type);
if (!Res) saveioerr=glob->ioerr;
CFSUnLock (glob,Parent);
if (!Res) glob->ioerr=saveioerr;
return Res;
}
else
{
debug (("** PANIC **: NULL object action func MakeLink() in lock.\n"));
CFSUnLock (glob,Parent);
glob->ioerr=ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSReadLink(glb glob,struct CFSLock *Parent,char *Name,char *Buffer,ULONG Size)
{
if ((Parent=CFSLockParent(glob,Parent,&Name))==NULL) return DOSFALSE;
if (Parent->f)
{
BOOL Res;
LONG saveioerr;
Res=(*Parent->f->ReadLink)(glob,Parent,Name,Buffer,Size);
if (!Res) saveioerr=glob->ioerr;
CFSUnLock (glob,Parent);
if (!Res) glob->ioerr=saveioerr;
return Res;
}
else
{
debug (("** PANIC **: NULL object action func ReadLink() in lock.\n"));
CFSUnLock (glob,Parent);
glob->ioerr=ERROR_OBJECT_WRONG_TYPE;
return DOSFALSE;
}
}
BOOL CFSSameLock( glb glob, struct CFSLock *l1, struct CFSLock *l2 ){
if(!l1 || !l2) return (BOOL) (l1==l2 ? TRUE : FALSE);
if( l1->objtype != l2->objtype ) return FALSE;
if( !l1->f ){
debug(("** PANIC **: CFSSameLock(): Bad action func in lock.\n"));
glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
return FALSE;
}else return (*l1->f->SameLock)(glob, l1, l2);
}
/* End of lock.c */